package org.dreamwork.cai.core;

import org.dreamwork.cai.SRFException;
import org.dreamwork.cai.srf.*;
import org.dreamwork.cai.tools.Const;
import org.dreamwork.concurrent.broadcast.ILocalBroadcastReceiver;
import org.dreamwork.concurrent.broadcast.ILocalBroadcastService;
import org.dreamwork.concurrent.broadcast.LocalMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 用于监听服务路由本地广播的接收器
 */
public class SRFBroadcastReceiver implements ILocalBroadcastReceiver {
    private final Logger logger = LoggerFactory.getLogger (SRFBroadcastReceiver.class);

    private final IRemoteServices services;
    private final Set<String> ignoredSRF = new HashSet<> ();
    private final Set<String> requiredSRF = new HashSet<> ();

    private boolean buildLocalStub = true;
    private ILocalBroadcastService broadcaster;

    public void setBuildLocalStub (boolean buildLocalStub) {
        this.buildLocalStub = buildLocalStub;
    }

    public SRFBroadcastReceiver (IRemoteServices services) {
        this.services = services;
    }

    public void setBroadcaster (ILocalBroadcastService broadcaster) {
        this.broadcaster = broadcaster;
    }

    public void addIgnoredSRF (String... names) {
        ignoredSRF.addAll (Arrays.asList (names));
    }

    public void addRequiredSRF (String... names) {
        requiredSRF.addAll (Arrays.asList (names));
    }

    @Override
    public void received (LocalMessage message) {
        switch (message.what) {
            case Const.SRF.UPDATE :
                if (buildLocalStub) {
                    try {
                        update ((ServiceRouteFrame) message.arg);
                    } catch (Exception ex) {
                        logger.warn (ex.getMessage (), ex);
                    }
                } else {
                    if (broadcaster != null) {
                        broadcaster.broadcast (Const.Category.CAT_SRF_EVENT, Const.SRF.BUILT, message.arg);
                    }
                }
                break;
            case Const.SRF.WITHDRAWN:
                if (buildLocalStub) {
                    withdrawn ((ServiceRouteFrame) message.arg);
                } else {
                    if (broadcaster != null) {
                        broadcaster.broadcast (Const.Category.CAT_SRF_EVENT, Const.SRF.DESTROY, message.arg);
                    }
                }
                break;
        }
    }

    /**
     * 从网络接收到一个 srf，注入到本地 spring context 中
     * @param srf srf
     * @throws ClassNotFoundException 无法加载类
     * @throws NoSuchMethodException 未找到方法
     * @throws SRFException 服务路由错误
     */
    private void update (ServiceRouteFrame srf) throws Exception {
        if (logger.isTraceEnabled ()) {
            logger.trace ("updating service route frame ...");
        }
        if ("local".equals (srf.namespace)) {
            if (logger.isTraceEnabled ()) {
                logger.trace ("the local srf updated, ignore it");
            }

            return;
        }

        if (included (srf.namespace)) {
            services.register (srf);
        }
    }

    private void withdrawn (ServiceRouteFrame srf) {
        services.remove (srf.namespace);
    }

    private boolean included (String namespace) {
        if (requiredSRF.contains (namespace) || (requiredSRF.isEmpty () && ignoredSRF.isEmpty ())) {
            // 在 requiredSRF 中指定了，-- 或者 -- requiredSRF 和 ignoredSRf 都未指定
            return true;
        }
        // 未配置过 requiredSRF，且不包含在 ignoredSRf 中，也必须构建
        return requiredSRF.isEmpty () && !ignoredSRF.contains (namespace);
    }
}